<?php

namespace W3;

use ErrorException;
use Throwable;

!defined('W3_ROOT_DIR') AND exit;

/**
 * 错误和异常处理
 *
 * @author edikud
 * @date 2022/10/22
 * @copyright Copyright (c) 2022 W3 (http://www.mcooo.com)
 * @license GNU General Public License 2.0
 */
class Error
{
    /**
     * 数组
     *
     * @var array
     */
    protected static $config = [
		'errorHandler' => ['\W3\Error', 'error'],
		'exceptionHandler' => ['\W3\Error', 'exception'],
		'shutdownHandler' => ['\W3\Error', 'shutdown'],
		'error404' => '',
		'log' => '',
	];

    /**
     * 获取和设置配置参数
     * @param string $method  参数名
     * @param mixed $arguments 参数值
     * @return mixed
     */
    public static function __callStatic($method, $arguments)
    {
        if(isset(self::$config[$method])){

			$argument = (!empty($arguments)) ? $arguments[0] : NULL;
			
			if(is_null($argument)) {
				
				return self::$config[$method];
			}
			
			self::$config[$method] = $argument;
		}
    }

    /**
     * 初始化
     * @access public
     * @return void
     */
    public static function init()
    {
		if(Config::instance()->debug) {
			
			error_reporting(E_ALL | E_STRICT);
			
			# 程序关闭时执行
            self::$config['shutdownHandler'] && register_shutdown_function(self::$config['shutdownHandler']);
			
		}else{
	
			# 关闭错误输出
			error_reporting(0);
		}

		function_exists('ini_set') && ini_set('display_errors', 'On');
		
		# 设置错误处理方法
        self::$config['errorHandler'] && set_error_handler(self::$config['errorHandler']);
			
		# 设置异常处理方法
        self::$config['exceptionHandler'] && set_exception_handler(self::$config['exceptionHandler']);
    }
	
    /**
     * 错误处理
     *
     * @param string $code
     * @param string $message
     * @param string $file
     * @param int    $line
     * @param array  $context
     *
     * @throws ErrorException
     */
    public static function error($code, $message, $file, $line)
    {
        if ($code & error_reporting()) {
            static::exception(new ErrorException($message, $code, 0, $file, $line));
        }
    }

    /**
     * 异常处理
     *
     * @param $e 异常对象
     *
     * @return void
     * @throws ErrorException
     */
    public static function exception($e)
    {
        if (!empty(self::$config['error' . $e->getCode()])) {

            return call_user_func(self::$config['error' . $e->getCode()], $e);
        }

		# 根据应用程序配置记录异常
		!empty(self::$config['log']) && call_user_func(self::$config['log'], $e);

        # 清除输出缓冲区
        while (ob_get_level() > 1) {
            ob_end_clean();
        }

        $msg = '<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>' .__('提示'). '</title>
        <style>
            * {
                margin:0px;
                padding:0px;
            }
            body{
				background-color: #f6f9fc;
            }
            .center {
                position:fixed;
                top:0;
                left:0;
                right:0;
                bottom:0;
                text-align:center;
                font-size:0;
                white-space: nowrap;
                overflow: hidden;
            }
            .center::after{
               content:\'\';
               display: inline-block;
               vertical-align: middle;
               height:100%;
            }
            .box {
                display: inline-block;
                vertical-align: middle;
                text-align: left;
                white-space: nowrap;
                max-width:100%;
				border-radius: 6px;
                background-color: #ebf1f7;
                padding:25px;
                font-size:15px;
                line-height:180%;
                color: #4a4e69;
				max-height:80%;
                overflow-y: auto;
            }
            code{
				background:#D1E751;
				border-radius:4px;
				padding:2px 6px
			}
            h2 {
				color: #4a4e69;
                margin:10px 0;
            }
            h3 {
				color: #7679bb;
				padding:6px 0
            }
        </style>
    </head>
    <body>
	    <div class="center">
            <div class="box">
                <h2 align="center">'. $e->getMessage() .'</h2>';
				
        if(Config::instance()->debug){
			$msg .= 
		        '<h3>Origin</h3>
		        <p><code>' . substr($e->getFile(), strlen(W3_ROOT_DIR)) . ' on line ' . $e->getLine() . '</code></p>
		        <h3>Trace</h3>
		        <pre>' . str_replace(W3_ROOT_DIR, '', $e->getTraceAsString()) . '</pre>';
	    }
		
		$msg .= 
            '</div>
		</div>
    </body>
</html>';
		
        try {
            Response::instance()
                ->clear()
                ->code(500)
                ->write($msg)
                ->send();
				exit;
        }
        catch (Throwable $t) { // PHP 7.0+
            exit($msg);
        }
    }

    /**
     * 程序关闭时执行
     *
     * @return void
     * @throws ErrorException
     */
    public static function shutdown()
    {
		# 确定错误类型是否致命
        if (!is_null($error = error_get_last()) && in_array($error['type'], [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE])) {

            static::exception(new ErrorException($error['type'], $error['message'], $error['file'], $error['line']));
        }
    }
}
